/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <iostream>
#include <memory>
#include <string>

#include <grpcpp/grpcpp.h>

//#ifdef BAZEL_BUILD
//#include "examples/protos/helloworld.grpc.pb.h"
//#else
//#include "gp.grpc.pb.h"
//#endif

#include "gp.grpc.pb.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using grpc::ClientReader;
using grpc::ClientReaderWriter;
using grpc::ClientWriter;

using gp::TryRequest;
using gp::NotifyMes;
using gp::DJ_Qpcr;

using namespace gp;

//using gp::HelloRequest;
//using gp::HelloReply;
using gp::QPCR;


typedef enum
{
  QPCR_OP_FILTER,
  QPCR_OP_PHOTO,
  QPCR_BATH_Z,
  QPCR_BATH_X,
  DJ_ADDSAMPLE,
  MAX_ELE_NUM_ALL
}en_ele_name;



class QpcrClient {
 public:
  QpcrClient(std::shared_ptr<Channel> channel)
      : stub_(QPCR::NewStub(channel)) {}

  // Assembles the client's payload, sends it and presents the response back
  // from the server.
  Response Qpcr_test(const AxisMoveParam movePAram,int eleNumIn) {
    // Data we are sending to the server.
   // AxisMoveParam movePAram;
    //request.set_name(user);

    // Container for the data we expect from the server.
    Response reply;

    // Context for the client. It could be used to convey extra information to
    // the server and/or tweak certain RPC behaviors.
    ClientContext context;
    Status status;
    switch(eleNumIn)
    {
       case QPCR_OP_FILTER:
       {
         status = stub_->OpticalFilter(&context, movePAram, &reply);
       }
       break;
       case QPCR_BATH_Z:
       {
         status = stub_->Bath_Z(&context, movePAram, &reply);
       }
       break;
       case QPCR_BATH_X:
       {
         status = stub_->Bath_X(&context, movePAram, &reply);
       }
       break;
       default:
       break;
    }

    // The actual RPC.
    

    // Act upon its status.
    if (status.ok()) {
      reply.set_statecode(100);
      return reply;
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      reply.set_statecode(1);      
      return reply;
    }
  }


  void NotifyTest(int idIn) {
    gp::TryRequest request;
    NotifyMes nmsg;
    ClientContext context;


    request.set_id(idIn);
    std::unique_ptr<ClientReader<NotifyMes> > reader(
        stub_->Notify(&context, request));
    while (reader->Read(&nmsg)) {
      std::cout <<"test content:" << nmsg.content()<<std::endl;
    }
    Status status = reader->Finish();
    if (status.ok()) {
      std::cout << "NotifyTest rpc succeeded." << std::endl;
    } else {
      std::cout << "NotifyTest rpc failed." << std::endl;
    }
  }

 private:
  std::unique_ptr<QPCR::Stub> stub_;
};

class DjClient {
 public:
  DjClient(std::shared_ptr<Channel> channel)
      : stub_(DJ_Qpcr::NewStub(channel)) {}

  // Assembles the client's payload, sends it and presents the response back
  // from the server.
  Response Dj_test(const AxisMoveParam movePAram,int eleNumIn) {
    // Data we are sending to the server.
   // AxisMoveParam movePAram;
    //request.set_name(user);

    // Container for the data we expect from the server.
    Response reply;

    // Context for the client. It could be used to convey extra information to
    // the server and/or tweak certain RPC behaviors.
    ClientContext context;
    Status status;
    //EmptyRequest emptyRequest;

    switch(eleNumIn)
    {
       case DJ_ADDSAMPLE:
       {
         DjAddSampleParam addSampleParam; 
         addSampleParam.set_traceline("Bh20,Bg20,Bf20,Be20,Bd20,Bc20,Bb20,Ba20,\
Ca20,Cb20,Cc20,Cd20,Ce20,Cf20,Cg20,Ch20");
          addSampleParam.set_initx(400);
          addSampleParam.set_inity(0);
          addSampleParam.set_initz(30000);

          addSampleParam.set_deltax(480);
          addSampleParam.set_deltay(8571);

          addSampleParam.set_quantityair(5);
          addSampleParam.set_quantitydrop(5);
          addSampleParam.set_quantitysuck(320);
         status = stub_->DJ_AddSample(&context, addSampleParam, &reply);
       }
       break;       
       default:
       break;
    }

    // The actual RPC.
    

    // Act upon its status.
    if (status.ok()) {
      reply.set_statecode(100);
      return reply;
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      reply.set_statecode(1);      
      return reply;
    }
  }
 private:
  std::unique_ptr<DJ_Qpcr::Stub> stub_;
};



int parseFile(const char * fileNameIn,AxisMoveParam * pstMoveParam,int &eleNum);

#define GRPC_TEST_FILE "test_cmd.txt"
//#define SYSTEM_SETUP_IP_PORT "10.6.3.74:1234"
#define SYSTEM_SETUP_IP_PORT "10.3.0.202:50051"

int main(int argc, char** argv) {
  // Instantiate the client. It requires a channel, out of which the actual RPCs
  // are created. This channel models a connection to an endpoint (in this case,
  // localhost at port 50051). We indicate that the channel isn't authenticated
  // (use of InsecureChannelCredentials()).
  
  std::string user("world");

  AxisMoveParam moveParam;
  moveParam.set_position(2000);
  moveParam.set_speed(2000);
  moveParam.set_acc(2000);
  moveParam.set_dec(2000);
  int numEle = MAX_ELE_NUM_ALL;
  if(argc>=2)
  {
    parseFile(argv[1],&moveParam,numEle);

    if(numEle>=MAX_ELE_NUM_ALL)
    {
      printf("get move param failed,filename:%s\n",argv[1]);
      parseFile(GRPC_TEST_FILE,&moveParam,numEle);
      if(numEle>=MAX_ELE_NUM_ALL)
      {
        printf("get move param failed,filename:%s\n",GRPC_TEST_FILE);
        return 1;
      }
      
    }
  }
  else
  {
    parseFile(GRPC_TEST_FILE,&moveParam,numEle);
    if(numEle>=MAX_ELE_NUM_ALL)
    {
      printf("get move param failed,filename:%s\n",GRPC_TEST_FILE);
      return 1;
    }
  }
  
  
  Response reply;
  printf("ip:port=%s,numEle:%d\n",SYSTEM_SETUP_IP_PORT,numEle);
  if( (QPCR_OP_FILTER==numEle)
    ||(numEle<=QPCR_BATH_X && numEle>=QPCR_BATH_Z))
  {
    
    QpcrClient qpcrClient(grpc::CreateChannel(
        SYSTEM_SETUP_IP_PORT, grpc::InsecureChannelCredentials()));
    reply = qpcrClient.Qpcr_test(moveParam,numEle);

    std::cout << "QpcrClient received: " << reply.statecode() << std::endl;
  }else if(QPCR_OP_PHOTO==numEle)
  {
    QpcrClient qpcrClient(grpc::CreateChannel(
        SYSTEM_SETUP_IP_PORT, grpc::InsecureChannelCredentials()));
    qpcrClient.NotifyTest(1);

    
  }
  else if(DJ_ADDSAMPLE == numEle)
  {
    DjClient djClient(grpc::CreateChannel(
        SYSTEM_SETUP_IP_PORT, grpc::InsecureChannelCredentials()));

    AxisMoveParam moveParam;
    memset(&moveParam,0,sizeof(AxisMoveParam));
    djClient.Dj_test(moveParam,DJ_ADDSAMPLE);
  }
  
  // else if(numEle == DROPTUBE_JAW)
  // {
  //   DP1Client dp1Client(grpc::CreateChannel(
  //       SYSTEM_SETUP_IP_PORT, grpc::InsecureChannelCredentials()));

  //   reply = dp1Client.Dp1_test(moveParam,numEle);
  // }

  return 0;
}

int parseFile(const char * fileNameIn,AxisMoveParam * pstMoveParam,int &eleNum)
{
  FILE * fp = fopen(fileNameIn,"r");
  if(fp==NULL)
  {
    eleNum = MAX_ELE_NUM_ALL;
    return 1;
  }

  char StrLine[256];
  char * tmpPtr = NULL;
  while(!feof(fp))
  {
      memset(StrLine,0,256);
      fgets(StrLine,256,fp);
      if(strstr(StrLine,"eleName"))
      {
          tmpPtr = StrLine + 8;
          if(strstr(tmpPtr,"opfilter"))
          {
            eleNum = QPCR_OP_FILTER;
            continue;
          }
          else if(strstr(tmpPtr,"photo"))
          {
            eleNum = QPCR_OP_PHOTO;
            continue;
          }
          else if(strstr(tmpPtr,"bathz"))
          {
            eleNum = QPCR_BATH_Z;
            continue;
          }
          else if(strstr(tmpPtr,"bathx"))
          {
            eleNum = QPCR_BATH_X;
            continue;
          }
          else if(strstr(tmpPtr,"dj_rea"))
          {
            eleNum = DJ_ADDSAMPLE;
            continue;
          }
      }

      if(strstr(StrLine,"pos"))
      {
          tmpPtr = StrLine+4;
          pstMoveParam->set_position(atoi(tmpPtr));
          continue;
      }

      if(strstr(StrLine,"inc"))
      {
          tmpPtr = StrLine+4;
          pstMoveParam->set_acc(strtoul(tmpPtr,NULL,0));
          continue;
      }

      if(strstr(StrLine,"dec"))
      {
          tmpPtr = StrLine+4;
          pstMoveParam->set_dec(atoi(tmpPtr));
          continue;
      }

      if(strstr(StrLine,"speed"))
      {
          tmpPtr = StrLine+6;
          pstMoveParam->set_speed(strtoul(tmpPtr,NULL,0));
          continue;
      }     

  }
  
  fclose(fp);
  return 0;
}
